 /* Copyright (c) 2007 Pentaho Corporation.  All rights reserved. 
 * This software was developed by Pentaho Corporation and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is Pentaho 
 * Data Integration.  The Initial Developer is samatar Hassan.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.*/
 
package org.pentaho.di.trans.steps.randomccnumber;

import java.util.List;
import java.util.Map;

import org.w3c.dom.Node;

import org.pentaho.di.core.CheckResult;
import org.pentaho.di.core.CheckResultInterface;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.Counter;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.core.exception.KettleXMLException;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.ValueMeta;
import org.pentaho.di.core.row.ValueMetaInterface;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.core.xml.XMLHandler;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStepMeta;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepIOMeta;
import org.pentaho.di.trans.step.StepIOMetaInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;


/**
 * Generate random credit card number.
 * 
 * @author Samatar
 * @since 01-4-2010
 */
public class RandomCCNumberGeneratorMeta extends BaseStepMeta implements StepMetaInterface {
	private static Class<?> PKG = RandomCCNumberGeneratorMeta.class; // for i18n purposes, needed by Translator2!!   $NON-NLS-1$

	private String fieldCCType[];
	private String fieldCCLength[];
	private String fieldCCSize[];
	
	private  String cardNumberFieldName;
	private  String cardLengthFieldName;
	private  String cardTypeFieldName;

	public RandomCCNumberGeneratorMeta() {
		super(); // allocate BaseStepMeta
	}

	/**
	 * @return Returns the fieldCCType.
	 */
	public String[] getFieldCCType() {
		return fieldCCType;
	}
    
    /**
     * @return Returns the cardNumberFieldName.
     */
    public String getCardNumberFieldName()
    {
        return cardNumberFieldName;
    }
    
    /**
     * @param cardNumberFieldName The cardNumberFieldName to set.
     */
    public void setCardNumberFieldName(String cardNumberFieldName)
    {
        this.cardNumberFieldName = cardNumberFieldName;
    }
    
    /**
     * @return Returns the cardLengthFieldName.
     */
    public String getCardLengthFieldName()
    {
        return cardLengthFieldName;
    }
    
    /**
     * @param cardLengthFieldName The cardLengthFieldName to set.
     */
    public void setCardLengthFieldName(String cardLengthFieldName)
    {
        this.cardLengthFieldName = cardLengthFieldName;
    }
    /**
     * @return Returns the cardTypeFieldName.
     */
    public String getCardTypeFieldName()
    {
        return cardTypeFieldName;
    }
    
    /**
     * @param cardTypeFieldName The cardTypeFieldName to set.
     */
    public void setCardTypeFieldName(String cardTypeFieldName)
    {
        this.cardTypeFieldName = cardTypeFieldName;
    }
	/**
	 * @param fieldName
	 *            The fieldCCType to set.
	 */
	public void setFieldCCType(String[] fieldName) {
		this.fieldCCType = fieldName;
	}

	/**
	 * @return Returns the fieldType.
	 */
	public String[] getFieldCCLength() {
		return fieldCCLength;
	}

	/**
	 * @return Returns the fieldCCSize.
	 */
	public String[] getFieldCCSize() {
		return fieldCCSize;
	}
	/**
	 * @param fieldType
	 *            The fieldType to set.
	 */
	public void setFieldType(String[] fieldType) {
		this.fieldCCLength = fieldType;
	}

	
	public void loadXML(Node stepnode, List<DatabaseMeta> databases,
			Map<String, Counter> counters) throws KettleXMLException {
		readData(stepnode);
	}

	public void allocate(int count) {
		fieldCCType = new String[count];
		fieldCCLength = new String[count];
		fieldCCSize = new String[count];
	}

	public Object clone() {
		RandomCCNumberGeneratorMeta retval = (RandomCCNumberGeneratorMeta) super.clone();

		int count = fieldCCType.length;

		retval.allocate(count);

		for (int i = 0; i < count; i++) {
			retval.fieldCCType[i] = fieldCCType[i];
			retval.fieldCCLength[i] = fieldCCLength[i];
			retval.fieldCCSize[i] = fieldCCSize[i];
		}

		return retval;
	}

	private void readData(Node stepnode) throws KettleXMLException {
		try {
			Node fields = XMLHandler.getSubNode(stepnode, "fields");
			int count = XMLHandler.countNodes(fields, "field");

			allocate(count);

			for (int i = 0; i < count; i++) {
				Node fnode = XMLHandler.getSubNodeByNr(fields, "field", i);

				fieldCCType[i] = XMLHandler.getTagValue(fnode, "cctype");
				fieldCCLength[i] = XMLHandler.getTagValue(fnode, "cclen");
				fieldCCSize[i] = XMLHandler.getTagValue(fnode, "ccsize");
			}

            cardNumberFieldName=XMLHandler.getTagValue(stepnode, "cardNumberFieldName");
            cardLengthFieldName=XMLHandler.getTagValue(stepnode, "cardLengthFieldName");
            cardTypeFieldName=XMLHandler.getTagValue(stepnode, "cardTypeFieldName");
		} catch (Exception e) {
			throw new KettleXMLException("Unable to read step information from XML", e);
		}
	}


	public void setDefault() {
		int count = 0;

		allocate(count);

		for (int i = 0; i < count; i++) {
			fieldCCType[i] = "field" + i;
			fieldCCLength[i] = "";
			fieldCCSize[i] = "";
		}
		cardNumberFieldName = BaseMessages.getString(PKG, "RandomCCNumberGeneratorMeta.CardNumberField");
		cardLengthFieldName = BaseMessages.getString(PKG, "RandomCCNumberGeneratorMeta.CardLengthField");
		cardTypeFieldName = BaseMessages.getString(PKG, "RandomCCNumberGeneratorMeta.CardTypeField");
	}

	public void getFields(RowMetaInterface row, String name,
			RowMetaInterface[] info, StepMeta nextStep, VariableSpace space)
			throws KettleStepException {

		ValueMetaInterface v = new ValueMeta(cardNumberFieldName, ValueMeta.TYPE_STRING);
		v.setOrigin(name);
		row.addValueMeta(v);
		
		if(!Const.isEmpty(getCardTypeFieldName())) {
			v = new ValueMeta(cardTypeFieldName, ValueMeta.TYPE_STRING);
			v.setOrigin(name);
			row.addValueMeta(v);
		}
		
		if(!Const.isEmpty(getCardLengthFieldName())) {
			v = new ValueMeta(cardLengthFieldName, ValueMeta.TYPE_INTEGER);
			v.setLength(ValueMeta.DEFAULT_INTEGER_LENGTH, 0);
			v.setOrigin(name);
			row.addValueMeta(v);
		}
		
	}

	public String getXML() {
		StringBuffer retval = new StringBuffer(200);

		retval.append("    <fields>").append(Const.CR);

		for (int i = 0; i < fieldCCType.length; i++) {
			retval.append("      <field>").append(Const.CR);
			retval.append("        ").append(XMLHandler.addTagValue("cctype", fieldCCType[i]));
			retval.append("        ").append(XMLHandler.addTagValue("cclen",fieldCCLength[i]));
			retval.append("        ").append(XMLHandler.addTagValue("ccsize",fieldCCSize[i]));
			retval.append("      </field>").append(Const.CR);
		}
		retval.append("    </fields>" + Const.CR);
		
		retval.append("    "+XMLHandler.addTagValue("cardNumberFieldName", cardNumberFieldName));
		retval.append("    "+XMLHandler.addTagValue("cardLengthFieldName", cardLengthFieldName));
		retval.append("    "+XMLHandler.addTagValue("cardTypeFieldName", cardTypeFieldName));
		return retval.toString();
	}

	public void readRep(Repository rep, ObjectId id_step,
			List<DatabaseMeta> databases, Map<String, Counter> counters)
			throws KettleException {
		try {
			int nrfields = rep.countNrStepAttributes(id_step, "field_name");

			allocate(nrfields);

			for (int i = 0; i < nrfields; i++) {
				fieldCCType[i] = rep.getStepAttributeString(id_step, i,"cctype");
				fieldCCLength[i] = rep.getStepAttributeString(id_step, i,"cclen");
				fieldCCSize[i] = rep.getStepAttributeString(id_step, i,"ccsize");
			}
            cardNumberFieldName = rep.getStepAttributeString(id_step, "cardNumberFieldName");
            cardLengthFieldName = rep.getStepAttributeString(id_step, "cardLengthFieldName");
            cardTypeFieldName = rep.getStepAttributeString(id_step, "cardTypeFieldName");

		} catch (Exception e) {
			throw new KettleException("Unexpected error reading step information from the repository", e);
		}
	}

	public void saveRep(Repository rep, ObjectId id_transformation, ObjectId id_step)
	throws KettleException {
		try {
			for (int i = 0; i < fieldCCType.length; i++) {
				rep.saveStepAttribute(id_transformation, id_step, i, "cctype", fieldCCType[i]);
				rep.saveStepAttribute(id_transformation, id_step, i, "cclen", fieldCCLength[i]);
				rep.saveStepAttribute(id_transformation, id_step, i, "ccsize", fieldCCSize[i]);
			}
			rep.saveStepAttribute(id_transformation, id_step, "cardNumberFieldName",      cardNumberFieldName);
			rep.saveStepAttribute(id_transformation, id_step, "cardLengthFieldName",      cardLengthFieldName);
			rep.saveStepAttribute(id_transformation, id_step, "cardTypeFieldName",      cardTypeFieldName);
		} catch (Exception e) {
			throw new KettleException( "Unable to save step information to the repository for id_step=" + id_step, e);
		}

	}

	public void check(List<CheckResultInterface> remarks, TransMeta transMeta,
			StepMeta stepMeta, RowMetaInterface prev, String input[],
			String output[], RowMetaInterface info) {
		// See if we have input streams leading to this step!
		int nrRemarks = remarks.size();
		for (int i = 0; i < fieldCCType.length; i++) {
			int len= Const.toInt(transMeta.environmentSubstitute(getFieldCCLength()[i]), -1);
			if (len<0) {
				CheckResult cr = new CheckResult(CheckResult.TYPE_RESULT_ERROR,BaseMessages.getString(PKG, "RandomCCNumberGeneratorMeta.CheckResult.WrongLen",String.valueOf(i)), stepMeta);
				remarks.add(cr);
			}
			int size= Const.toInt(transMeta.environmentSubstitute(getFieldCCSize()[i]), -1);
			if (size<0) {
				CheckResult cr = new CheckResult(CheckResult.TYPE_RESULT_ERROR,BaseMessages.getString(PKG, "RandomCCNumberGeneratorMeta.CheckResult.WrongSize",String.valueOf(i)), stepMeta);
				remarks.add(cr);
			}	
		}
		if (remarks.size() == nrRemarks) {
			CheckResult cr = new CheckResult(CheckResult.TYPE_RESULT_OK,BaseMessages.getString(PKG, "RandomCCNumberGeneratorMeta.CheckResult.AllTypesSpecified"),stepMeta);
			remarks.add(cr);
		}
		
		if(Const.isEmpty(getCardNumberFieldName())) {
			CheckResult cr = new CheckResult(CheckResult.TYPE_RESULT_ERROR,BaseMessages.getString(PKG, "RandomCCNumberGeneratorMeta.CheckResult.CardNumberFieldMissing"), stepMeta);
			remarks.add(cr);
		}
	}

	public StepInterface getStep(StepMeta stepMeta,
			StepDataInterface stepDataInterface, int cnr, TransMeta transMeta,
			Trans trans) {
		return new RandomCCNumberGenerator(stepMeta, stepDataInterface, cnr, transMeta,	trans);
	}

	public StepDataInterface getStepData() {
		return new RandomCCNumberGeneratorData();
	}
	/**
     * Returns the Input/Output metadata for this step.
     * The generator step only produces output, does not accept input!
     */
    public StepIOMetaInterface getStepIOMeta() {
    	return new StepIOMeta(false, true, false, false, false, false);
    }
}